import javax.swing.JFrame;          // 导入Swing框架的窗口类
import javax.swing.JPanel;          // 导入面板类，用于组织界面组件
import javax.swing.JTextField;      // 导入文本框类，用于显示计算过程和结果
import javax.swing.JOptionPane;    // 导入对话框类，用于显示提示信息
import javax.swing.JLabel;         // 导入标签类，用于自定义对话框内容
import javax.script.ScriptEngine;   // 导入脚本引擎接口，用于计算表达式
import javax.script.ScriptEngineManager; // 导入脚本引擎管理器，用于创建脚本引擎
import javax.script.ScriptException; // 导入脚本异常类，用于处理计算错误
import javax.swing.JButton;         // 导入按钮类，用于创建操作按钮
import javax.swing.SwingUtilities;  // 导入Swing工具类，用于线程安全地更新UI
import javax.swing.Timer;           // 导入定时器类，用于时间显示和定时任务

import javafx.application.Platform;  // 导入JavaFX平台类，用于在JavaFX线程中操作媒体播放器
import javafx.embed.swing.JFXPanel;  // 导入JavaFX与Swing集成面板，用于初始化JavaFX环境
import javafx.scene.media.Media;     // 导入JavaFX媒体类，用于加载音频文件
import javafx.scene.media.MediaPlayer; // 导入JavaFX媒体播放器类，用于播放音频
import java.io.File;                 // 导入文件类，用于读取音频文件路径

import java.awt.Color;              // 导入颜色类，用于设置组件颜色
import java.awt.Font;               // 导入字体类，用于设置文本字体
import java.awt.Dimension;          // 导入尺寸类，用于设置组件大小
import java.awt.GridLayout;         // 导入网格布局类，用于按钮布局
import java.awt.BorderLayout;       // 导入边界布局类，用于面板布局
import java.awt.event.ActionEvent;  // 导入动作事件类，用于事件处理
import java.awt.event.ActionListener; // 导入动作监听器接口，用于处理按钮点击
import java.time.LocalDateTime;     // 导入本地日期时间类，用于获取当前时间
import java.time.format.DateTimeFormatter; // 导入日期时间格式化类，用于格式化时间显示

/**
 * 高级计算器类，继承自JFrame，实现ActionListener接口处理按钮点击事件
 */
public class Calculator extends JFrame implements ActionListener {

    private MediaPlayer mediaPlayer = null;  // 媒体播放器，用于播放背景音乐
    private boolean isMusicPlaying = false;  // 音乐播放状态标志
    private boolean isMusicPaused = false;   // 音乐暂停状态标志

    private boolean isTimeShowing = false;   // 时间显示状态标志
    private Timer timeTimer;                 // 定时器，用于更新时间显示
    private String userInput = "";           // 存储用户输入的表达式
    private boolean inNumberMode = false;    // 数字输入模式标志，用于处理连续输入

    private final Color INPUT_BG_COLOR = Color.WHITE;           // 输入框背景色
    private final Color NUMBER_BTN_COLOR = new Color(255, 255, 204);  // 数字按钮背景色
    private final Color OPERATOR_BTN_COLOR = new Color(255, 204, 204);  // 操作符按钮背景色（浅粉色）

    private JPanel north, center;  // 界面布局面板：北部面板和中央面板
    private JTextField field;      // 显示计算过程和结果的文本框
    private JButton[] btns;        // 计算器按钮数组

    /**
     * 构造函数：初始化计算器界面和组件
     */
    public Calculator() {
        setTitle("高级计算器");            // 设置窗口标题
        setSize(1000, 1200);             // 设置窗口大小
        setDefaultCloseOperation(EXIT_ON_CLOSE);  // 设置关闭操作
        setLocationRelativeTo(null);     // 窗口居中显示
        initComponent();                 // 初始化界面组件
        new JFXPanel();                  // 初始化JavaFX环境，用于媒体播放
        setVisible(true);                // 显示窗口
        setBackground(Color.gray);       // 设置窗口背景色
        playMusic();                     // 播放背景音乐
    }

    /**
     * 初始化界面组件：创建文本框和按钮，设置布局和样式
     */
    private void initComponent() {
        north = new JPanel();            // 创建北部面板（用于放置文本框）
        center = new JPanel();           // 创建中央面板（用于放置按钮）
        field = new JTextField();        // 创建文本框
        
        // 设置文本框属性：大小、不可编辑、字体和背景色
        field.setPreferredSize(new Dimension(700, 150));
        field.setEditable(false);
        field.setFont(new Font("SansSerif", Font.BOLD, 25));
        field.setBackground(INPUT_BG_COLOR);

        // 定义计算器按钮文本数组，按网格布局排列
        String[] str = new String[]{
            "√", "1/x", "x²", "log",      // 新增数学功能按钮（第一行）
            "7", "8", "9", "+",
            "4", "5", "6", "-",
            "1", "2", "3", "×",
            "0", ".", "=", "÷",
            "C", "B", "T", "S"
        };

        // 定义数字字符和操作符字符数组，用于设置按钮颜色
        String[] numberChars = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "="};
        String[] operatorChars = {"+", "-", "×", "÷", "S", "T", "B", "C", "√", "1/x", "x²", "log"};

        // 创建按钮数组并设置字体
        btns = new JButton[str.length];
        for (int i = 0; i < btns.length; i++) {
            btns[i] = new JButton(str[i]);
            btns[i].setFont(new Font("SansSerif", Font.BOLD, 25));
        }

        // 设置按钮背景色：数字按钮和操作符按钮使用不同颜色
        for (JButton btn : btns) {
            String text = btn.getText();
            if (isInArray(text, numberChars)) {
                btn.setBackground(NUMBER_BTN_COLOR);  // 数字按钮使用浅黄色
            } else if (isInArray(text, operatorChars)) {
                btn.setBackground(OPERATOR_BTN_COLOR);  // 操作符按钮使用浅粉色
            }
        }

        // 设置面板布局：北部面板使用边界布局，中央面板使用6x4网格布局
        north.setLayout(new BorderLayout());
        center.setLayout(new GridLayout(6, 4));

        // 将文本框添加到北部面板中央
        north.add(field, BorderLayout.CENTER);
        
        // 将所有按钮添加到中央面板
        for (JButton btn : btns) {
            center.add(btn);
        }
        
        // 将北部面板和中央面板添加到窗口
        add(north, BorderLayout.NORTH);
        add(center);

        // 为所有按钮添加动作监听器
        for (JButton btn : btns) {
            btn.addActionListener(this);
        }
        
        // 初始化时间定时器，每秒触发一次更新时间
        timeTimer = new Timer(1000, e -> updateTime());
        timeTimer.setRepeats(true);
    }

    /**
     * 更新时间显示：获取当前系统时间并格式化为"yyyy-MM-dd HH:mm:ss"
     */
    private void updateTime() {
        String currentTime = LocalDateTime.now()
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        field.setText(currentTime);
    }

    /**
     * 处理按钮点击事件：根据按钮文本执行相应操作
     */
    private void setBtnText(String text) {
        try {
            String currentText = field.getText();  // 获取当前文本框内容

            // 处理前导零：如果当前文本以"0"开头且不是"0."，则清空文本
            if (currentText.startsWith("0") && !currentText.startsWith("0.") && isNumber(text)) {
                currentText = "";
            }

            // 如果当前显示音乐状态，点击按钮时清空文本
            if (currentText.startsWith("音乐")) {
                currentText = "";
            }

            // 根据按钮文本执行不同操作
            switch (text) {
                case "C":  // 清空按钮
                    field.setText("");
                    inNumberMode = false;
                    break;
                case "B":  // 退格按钮
                    if (currentText.length() != 0) {
                        String lastText = currentText.substring(0, currentText.length() - 1);
                        field.setText(lastText);
                        inNumberMode = !isLastCharOperator(lastText);
                    }
                    break;
                case "T":  // 时间显示按钮
                    isTimeShowing = !isTimeShowing;
                    if (isTimeShowing) {
                        userInput = currentText;  // 保存当前输入
                        timeTimer.start();        // 启动定时器
                        updateTime();             // 更新时间显示
                    } else {
                        timeTimer.stop();         // 停止定时器
                        field.setText(userInput); // 恢复之前的输入
                        inNumberMode = !isLastCharOperator(userInput);
                    }
                    break;
                case "S":  // 音乐控制按钮
                    if (isMusicPlaying) {
                        pauseMusic();  // 暂停音乐
                    } else {
                        playMusic();   // 播放音乐
                    }
                    break;
                case "=":  // 等号按钮：执行计算
                    calculate();
                    inNumberMode = true;
                    break;
                case ".":  // 小数点按钮
                    if (inNumberMode && !hasDecimalPoint(currentText)) {
                        field.setText(currentText + text);  // 当前是数字模式且没有小数点时添加小数点
                    } else {
                        if (currentText.isEmpty() || isLastCharOperator(currentText)) {
                            field.setText("0.");  // 空输入或最后一个字符是操作符时添加"0."
                            inNumberMode = true;
                        }
                    }
                    break;
                // 数学功能按钮处理
                case "√":  // 平方根
                    processMathFunction("Math.sqrt(", ")");
                    break;
                case "1/x":  // 倒数
                    processMathFunction("1/", "");
                    break;
                case "x²":  // 平方
                    processMathFunction("Math.pow(", ",2)");
                    break;
                case "log":  // 自然对数
                    processMathFunction("Math.log(", ")");
                    break;
                default:  // 其他按钮（数字和操作符）
                    if (!isTimeShowing) {
                        if (isNumber(text)) {
                            field.setText(currentText + text);  // 添加数字
                            inNumberMode = true;
                        } else if (text.equals(".")) {
                            if (inNumberMode && !hasDecimalPoint(currentText)) {
                                field.setText(currentText + text);  // 添加小数点
                            }
                        } else if (isOperator(text)) {
                            // 处理操作符：允许负号作为表达式开头，避免连续操作符
                            if (text.equals("-") && currentText.isEmpty()) {
                                field.setText(currentText + text);  // 允许负号作为开头
                                inNumberMode = false;
                            } else if (!currentText.isEmpty() && !isLastCharOperator(currentText)) {
                                field.setText(currentText + text);  // 添加操作符
                                inNumberMode = false;
                            } else {
                                throw new IllegalArgumentException("符号不能连续出现");
                            }
                        }
                    }
                    break;
            }
        } catch (Exception e) {
            showErrorDialog(e.getMessage());  // 捕获异常并显示错误对话框
        }
    }

    /**
     * 处理数学函数计算：构建并计算数学表达式
     * @param prefix 函数前缀（如"Math.sqrt("）
     * @param suffix 函数后缀（如")"）
     */
    private void processMathFunction(String prefix, String suffix) throws IllegalArgumentException {
        String currentText = field.getText();
        if (currentText.isEmpty()) {
            throw new IllegalArgumentException("请先输入数值");
        }
        
        try {
            double value = Double.parseDouble(currentText);  // 将文本转换为数值
            
            // 检查特定函数的有效性
            if (prefix.equals("Math.sqrt(") && value < 0) {
                throw new IllegalArgumentException("平方根运算不能处理负数");
            }
            
            if (prefix.equals("Math.log(") && value <= 0) {
                throw new IllegalArgumentException("对数运算的输入必须是正数");
            }
            
            // 1/x运算检查分母是否为0
            if (prefix.equals("1/") && value == 0) {
                throw new IllegalArgumentException("除数不能为0");
            }
            
            // 构建JavaScript表达式并计算
            String expression = prefix + currentText + suffix;
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("javascript");
            Object result = engine.eval(expression);
            field.setText(result.toString());  // 显示计算结果
            inNumberMode = true;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("无效的数值格式");
        } catch (ScriptException e) {
            throw new IllegalArgumentException("计算错误: " + e.getMessage());
        }
    }

    /**
     * 显示自定义错误对话框：使用大字体和适当尺寸显示错误信息
     */
    private void showErrorDialog(String message) {
        JLabel messageLabel = new JLabel(message);
        messageLabel.setFont(new Font("SansSerif", Font.BOLD, 24));
        
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(messageLabel, BorderLayout.CENTER);
        panel.setPreferredSize(new Dimension(400, 200));
        
        JOptionPane.showMessageDialog(this, panel, "运算错误", JOptionPane.ERROR_MESSAGE);
    }

    /**
     * 判断字符是否为数字
     */
    private boolean isNumber(String text) {
        return text.matches("[0-9]");
    }

    /**
     * 判断字符是否为操作符
     */
    private boolean isOperator(String text) {
        return text.equals("+") || text.equals("-") || text.equals("×") || text.equals("÷") ||
               text.equals("√") || text.equals("1/x") || text.equals("x²") || text.equals("log");
    }

    /**
     * 判断文本的最后一个字符是否为操作符
     */
    private boolean isLastCharOperator(String text) {
        if (text.isEmpty()) {
            return false;
        }
        String lastChar = text.substring(text.length() - 1);
        return isOperator(lastChar);
    }

    /**
     * 判断当前数值部分是否包含小数点
     */
    private boolean hasDecimalPoint(String text) {
        if (text.isEmpty()) {
            return false;
        }
        int lastOperatorIndex = -1;
        
        // 查找最后一个操作符的位置
        for (int i = 0; i < text.length(); i++) {
            String charAt = text.substring(i, i + 1);
            if (isOperator(charAt) && !charAt.equals("√") && !charAt.equals("1/x") && 
                !charAt.equals("x²") && !charAt.equals("log")) {
                lastOperatorIndex = i;
            }
        }
        
        // 获取最后一个操作符后的数字部分，检查是否包含小数点
        String numberPart = lastOperatorIndex == -1 ? text : text.substring(lastOperatorIndex + 1);
        return numberPart.contains(".");
    }

    /**
     * 计算表达式结果：处理等号按钮的点击事件
     */
    private void calculate() {
        try {
            String expression = field.getText();
            
            // 检查除以零错误
            if (expression.contains("/0") || expression.contains("÷0")) {
                throw new IllegalArgumentException("0不能做除数");
            }
            
            // 将乘除符号转换为JavaScript支持的格式
            expression = expression.replace("×", "*").replace("÷", "/");
            
            // 使用JavaScript引擎计算表达式
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("javascript");
            Object result = engine.eval(expression);
            field.setText(result.toString());  // 显示计算结果
        } catch (ScriptException e) {
            showErrorDialog("表达式格式错误: " + e.getMessage());
        } catch (Exception e) {
            showErrorDialog(e.getMessage());
        }
    }

    /**
     * 播放背景音乐：在JavaFX线程中操作媒体播放器
     */
    private void playMusic() {
        Platform.runLater(() -> {
            if (mediaPlayer == null) {
                // 指定音乐文件路径（需要根据实际情况修改）
                String musicPath = "C:\\Users\\86151\\Desktop\\_- Merry Christmas Mr. Lawrence (1).wav";
                Media media = new Media(new File(musicPath).toURI().toString());
                mediaPlayer = new MediaPlayer(media);
                
                // 设置音乐播放结束后的回调
                mediaPlayer.setOnEndOfMedia(() -> {
                    isMusicPlaying = false;
                    isMusicPaused = false;
                    Platform.runLater(() -> field.setText("音乐播放结束"));
                });
            }
            
            // 播放音乐
            if (!isMusicPlaying) {
                if (isMusicPaused) {
                    mediaPlayer.play();  // 恢复播放
                } else {
                    mediaPlayer.play();  // 从头开始播放
                }
                isMusicPlaying = true;
                isMusicPaused = false;
                field.setText("音乐播放中...");
            }
        });
    }

    /**
     * 暂停背景音乐：在JavaFX线程中操作媒体播放器
     */
    private void pauseMusic() {
        Platform.runLater(() -> {
            if (mediaPlayer != null && isMusicPlaying && !isMusicPaused) {
                mediaPlayer.pause();  // 暂停播放
                isMusicPaused = true;
                isMusicPlaying = false;
                field.setText("音乐已暂停");
            }
        });
    }

    /**
     * 判断字符串是否在数组中
     */
    private boolean isInArray(String str, String[] array) {
        for (String s : array) {
            if (s.equals(str)) return true;
        }
        return false;
    }

    /**
     * 实现ActionListener接口的方法：处理按钮点击事件
     */
    @Override
    public void actionPerformed(ActionEvent a) {
        Object source = a.getSource();
        if (source instanceof JButton) {
            JButton btn = (JButton) source;
            String text = btn.getText();
            setBtnText(text);  // 调用按钮处理方法
        }
    }

    /**
     * 主方法：程序入口点，在事件调度线程中创建计算器实例
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(Calculator::new);
    }
}